package com.yonyougov.devops.cruxcisupport.server;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yonyougov.devops.cruxcisupport.enums.ServerStatusEnum;
import com.yonyougov.devops.cruxcisupport.role.RoleEntity;
import com.yonyougov.devops.cruxcisupport.role.RoleService;
import com.yonyougov.devops.cruxcisupport.server.dto.ExecuteCmdCommandDto;
import com.yonyougov.devops.cruxcisupport.server.dto.SearchDto;
import com.yonyougov.devops.cruxcisupport.server.dto.ServerPageLikeDto;
import com.yonyougov.devops.cruxcisupport.server.vo.*;
import com.yonyougov.devops.cruxcisupport.threadlocal.ErrorMessageThreadLocal;
import com.yonyougov.devops.cruxcisupport.user.UserEntity;
import com.yonyougov.devops.cruxcisupport.user.UserService;
import com.yonyougov.devops.cruxcisupport.userserver.UserServerEntity;
import com.yonyougov.devops.cruxcisupport.userserver.UserServerService;
import com.yonyougov.devops.cruxcisupport.util.EntityUtils;
import com.yonyougov.devops.cruxcisupport.util.Iputils;
import com.yonyougov.devops.cruxcisupport.util.SshUtil;
import com.yonyougov.devops.fwc.core.dao.BaseDao;
import com.yonyougov.devops.fwc.core.entity.Pagination;
import com.yonyougov.devops.fwc.core.service.impl.BaseServiceImpl;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

/**
 * t_server服务实现
 */
@Slf4j
@Service
public class ServerServiceImpl extends BaseServiceImpl<ServerEntity, BigInteger> implements ServerService {
    private ServerDao serverDao;
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private UserServerService userServerService;

    public ServerServiceImpl(ServerDao serverDao) {
        this.serverDao = serverDao;
    }

    @Override
    public BaseDao<ServerEntity, BigInteger> getDao() {
        return serverDao;
    }


    @Override
    public Pagination<ServerPageLikeRespVoParams> findAllByParamsLike(ServerPageLikeDto serverPageLikeDto) throws Exception {
        // 定义结果集
        List<ServerPageLikeRespVoParams> datas = new ArrayList<>();
        int totalCount = 0;
        // 如果用户名称为admin或者角色名称为admin,则查询全部; 否则只查询当前用户所关联的服务器
        UserEntity currentUser = userService.getCurrentUser();
        List<RoleEntity> currentUserRoles = roleService.getCurrentUserRoles();
        List<String> adminUserNameListFormCurrentUser = Arrays.asList(currentUser).stream().map(UserEntity::getUserName).filter(e -> "admin".equals(e)).collect(Collectors.toList());
        List<String> adminRoleNameListFormCurrentUser = currentUserRoles.stream().map(RoleEntity::getRoleName).filter(e -> "admin".equals(e)).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(adminUserNameListFormCurrentUser) || CollectionUtils.isNotEmpty(adminRoleNameListFormCurrentUser)) {

        } else {
            serverPageLikeDto.setUserIdIn(Arrays.asList(currentUser.getId()));
        }
        datas = serverDao.findAllByParamsLike(serverPageLikeDto);
        totalCount = serverDao.countByLikeServer(serverPageLikeDto);
        return new Pagination<>(serverPageLikeDto.getMax(), serverPageLikeDto.getPageNum(), totalCount, datas);
    }

    @Override
    public int countByLikeServer(ServerPageLikeDto serverPageLikeReqVoParams) {
        return serverDao.countByLikeServer(serverPageLikeReqVoParams);
    }

    @Override
    public String dialingTest(ServerEntity serverEntity) {
        SshUtil sshUtil = new SshUtil();
        return sshUtil.exeCmd(serverEntity, "ls");
    }

    @Override
    public Pagination<NoLinkServerRespVo> findNoLinkServerByUserId(NoLinkServerDto noLinkServerDto) {
        List<NoLinkServerRespVo> datas = serverDao.findNoLinkServerByUserId(noLinkServerDto);
        int totalCount = serverDao.findNoLinkServerByUserIdCount(noLinkServerDto);
        return new Pagination<>(noLinkServerDto.getMax(), noLinkServerDto.getPageNum(), totalCount, datas);
    }

    @Override
    public List<NoLinkServerRespVo> findNoLinkServerByEnvId(EnvNoLinkServerPageParams pageParams) {
        return serverDao.findNoLinkServerByEnvId(pageParams);
    }

    @Override
    public int findNoLinkServerByEnvIdCount(EnvNoLinkServerPageParams pageParams) {
        return serverDao.findNoLinkServerByEnvIdCount(pageParams);
    }

    @Override
    public void batchUpdateServerStatus(List<ServerStatusVo> statusVos) {
        serverDao.batchUpdateServerStatus(statusVos);
    }

    @Override
    public ExecuteCmdCommandVo executeCmdCommand(ExecuteCmdCommandDto executeCmdCommandDto) throws Exception {
        // 定义返回结果
        ExecuteCmdCommandVo executeCmdCommandVo = ExecuteCmdCommandVo.builder().results(new ArrayList<>()).build();

        List<ServerEntity> servers = serverDao.findByIds(executeCmdCommandDto.getServerList().stream().map(ServerEntity::getId).collect(Collectors.toList()));
        for (ServerEntity server : servers) {
            if (Objects.nonNull(server)) {
                SshUtil sshUtil = new SshUtil();
                String result = sshUtil.exeCmd(server, executeCmdCommandDto.getCmd());
                if (result != null) {
                    executeCmdCommandVo.getResults().add(result);
                } else {
                    executeCmdCommandVo.getResults().add("Connection timed out: connect");
                }
            } else {
                executeCmdCommandVo.getResults().add(String.format("id={}的服务器不存在", server.getId()));
            }
        }

        return executeCmdCommandVo;
    }

    /**
     * 注册主机
     * @param ip
     * @param hostname
     * @param port
     * @param remark
     */
    @Override
    public void registr(String ip, String hostname, String port, String remark) throws JsonProcessingException {
        ServerEntity serverEntity = ServerEntity.builder().connectType(1).ip(ip).name(hostname).port(Integer.valueOf(port)).state(1).username("root").remark(remark).build();
        log.info("注册主机 " + objectMapper.writeValueAsString(serverEntity));
        serverDao.insert(serverEntity);
    }

    /**
     * 刷新服务器状态
     * @param id t_server表id
     */
    @SneakyThrows
    @Override
    public void refreshServerStatus(BigInteger id) {
        List<ServerEntity> servers = new ArrayList<>();
        List<ServerEntity> upServers = new ArrayList<>();
        List<ServerEntity> downServers = new ArrayList<>();
        List<ServerEntity> unAuthServers = new ArrayList<>();
        Set<UserServerEntity> needAddUserServers = new HashSet<>();
        Map<String,Set<ServerEntity>> publicKeyServerMapCache = new HashMap<>();
        Map<String,Set<UserEntity>> publicKeyUserMapCache = new HashMap<>();
        StringJoiner errorMessage = new StringJoiner("<br/><br/>");

        if (id.equals(BigInteger.valueOf(-1))) {// 刷新全部服务器状态
            ServerEntity build = ServerEntity.builder().build();
            build.setPageAble(false);
            servers = serverDao.findAllBy(build);
        }else{// 刷新特定一个服务器状态
            servers = Arrays.asList(serverDao.findBy(ServerEntity.builder().id(id).build()));
        }

        // 认证检测 ip+端口检测
        ArrayList<Thread> mulThread = new ArrayList<>();
        for (ServerEntity server : servers) {
            mulThread.add(new Thread(()->{
                SshUtil sshUtil = new SshUtil();
                try {
                    // 拿到所有公钥，并产生服务器和公钥的缓存
                    String result = sshUtil.exeCmd(server, "cat /root/.ssh/authorized_keys",10000);
                    if (null != result) {
                        upServers.add(server);
                        for (String publicKey : Arrays.asList(result.replace("\n", ",").split(","))) {
                            publicKey = publicKey.trim();
                            if(publicKey.equals("")) continue;
                            if(!publicKeyServerMapCache.containsKey(publicKey)) publicKeyServerMapCache.put(publicKey,new HashSet<>());
                            publicKeyServerMapCache.get(publicKey).add(server);
                        }
                    } else if (Iputils.checkIpPort(server.getIp(),server.getPort(),10000)) {
                        unAuthServers.add(server);
                    }else{
                        downServers.add(server);
                    }
                } catch (Exception e) {
                    downServers.add(server);
                }
            }));
            mulThread.get(mulThread.size() - 1).start();
        }
        for (Thread thread : mulThread) {
            thread.join();
        }

        // 状态更新
        if (upServers.size()>0) {
            serverDao.batchUpdateServerStatus(
                upServers.stream().map(e -> ServerStatusVo.builder().hostname(e.getName()).state(ServerStatusEnum.ONLINE.getCode()).build()).collect(Collectors.toList())
            );
        }
        if (downServers.size()>0) {
            serverDao.batchUpdateServerStatus(
                downServers.stream().map(e -> ServerStatusVo.builder().hostname(e.getName()).state(ServerStatusEnum.OFFLINE.getCode()).build()).collect(Collectors.toList())
            );
        }
        if (unAuthServers.size()>0) {
            serverDao.batchUpdateServerStatus(
                unAuthServers.stream().map(e -> ServerStatusVo.builder().hostname(e.getName()).state(ServerStatusEnum.UNAUTH.getCode()).build()).collect(Collectors.toList())
            );
        }

        // 根据服务器公钥注册用户和服务器的关系
        UserEntity buildUser = UserEntity.builder().build();
        buildUser.setPageAble(false);
        List<UserEntity> allUsers = userService.findAllBy(buildUser).getDatas();
        for (UserEntity user : allUsers) {
            if (null != user.getPublicKey()) {
                for (String publicKey : user.getPublicKey().split(",")) {
                    publicKey = publicKey.trim();
                    if(!publicKeyUserMapCache.containsKey(publicKey)) publicKeyUserMapCache.put(publicKey,new HashSet<>());
                    publicKeyUserMapCache.get(publicKey).add(user);
                }
            }
        }
        UserServerEntity buildUserServer = UserServerEntity.builder().build();
        buildUserServer.setPageAble(false);
        List<UserServerEntity> allUserServers = userServerService.findAllBy(buildUserServer).getDatas();
        Map<String, UserServerEntity> allUserServersMap = allUserServers.stream().collect(Collectors.toMap(e -> "" + e.getUserId() + e.getServerId(), e -> e));
        for (Map.Entry<String, Set<ServerEntity>> entry : publicKeyServerMapCache.entrySet()) {
            String publicKey = entry.getKey();
            Set<ServerEntity> hasPublicKeyServers = entry.getValue();
            Set<UserEntity> hasPublickeyUsers = Optional.ofNullable(publicKeyUserMapCache.get(publicKey)).orElseGet(()->new HashSet<>());
            for (ServerEntity hasPublicKeyServer : hasPublicKeyServers) {
                if(hasPublickeyUsers.size()>0){
                    for (UserEntity hasPublickeyUser : hasPublickeyUsers) {
                        if(!allUserServersMap.containsKey(""+hasPublickeyUser.getId()+hasPublicKeyServer.getId())){
                            UserServerEntity userServerEntity = new UserServerEntity();
                            userServerEntity.setUserId(hasPublickeyUser.getId());
                            userServerEntity.setServerId(hasPublicKeyServer.getId());
                            needAddUserServers.add(userServerEntity);
                        }
                    }
                }else{
                    String[] publicKeyList = publicKey.split(" ");
                    if(publicKeyList.length == 3){
                        errorMessage.add(hasPublicKeyServer.getIp() + ":" + hasPublicKeyServer.getPort() +
                                "下" + publicKeyList[2] + "未找到用户");
                    }else{
                        errorMessage.add(hasPublicKeyServer.getIp() + ":" + hasPublicKeyServer.getPort() +
                                "下" + publicKey + "格式不对，请移除");
                    }

                }
            }
        }
        if (needAddUserServers.size()>0) {
            userServerService.addAll(needAddUserServers.stream().collect(Collectors.toList()));
        }
        ErrorMessageThreadLocal.setMessage(errorMessage.toString());
    }

    /**
     * 全文检索
     * @param searchDto 关键字
     * @return 服务实体类
     */
    @SneakyThrows
    @Override
    public Pagination<ServerSearchVo> search(SearchDto searchDto){
        String key = searchDto.getKey();

        List<ServerSearchVo> needRetureServers = new ArrayList<>();
        List<ServerSearchVo> currentServers = new ArrayList<>();
        Map<BigInteger, UserEntity> id2userMap = userService.findAllBy(EntityUtils.closePage(UserEntity.builder().build())).getDatas().stream().collect(Collectors.toMap(UserEntity::getId, e -> e));

        currentServers = serverDao.findAllBy(EntityUtils.closePage(ServerEntity.builder().build())).stream().map(e->new ServerSearchVo(e,null)).collect(Collectors.toList());
        needRetureServers.addAll(currentServers);

        // 添加申请人
        for (ServerSearchVo needRetureServer : needRetureServers) {
            needRetureServer.setCreateUser(id2userMap.get(needRetureServer.getCreateUserId()));
        }

        // 权限过滤
        Map<String, List<ServerSearchVo>> currentId2ServerMap = currentServers.stream().collect(Collectors.groupingBy(e -> e.getId().toString()));
        if ( !userService.getCurrentUser().getUserName().equals("admin")
            && !roleService.getCurrentUserRoles().stream().map(RoleEntity::getRoleName).collect(Collectors.toList()).contains("admin")) {
            List<UserServerEntity> userServers = userServerService.findAllBy(EntityUtils.closePage(UserServerEntity.builder().userId(userService.getCurrentUser().getId()).build())).getDatas();
            for (UserServerEntity userServer : userServers) {
                needRetureServers.addAll(currentId2ServerMap.get(userServer.getServerId().toString()));
            }
        }

        // key过滤
        currentServers.clear();
        currentServers.addAll(needRetureServers);
        needRetureServers.clear();
        StringJoiner stringJoiner = null;
        for (ServerSearchVo item : currentServers) {
            stringJoiner = new StringJoiner("");
            stringJoiner.add(item.getName());
            stringJoiner.add(item.getIp());
            stringJoiner.add(item.getPort().toString());
            stringJoiner.add(item.getUsername());
            stringJoiner.add(item.getRemark());
            if (item.getState().equals(ServerStatusEnum.OFFLINE.getCode())) {
                stringJoiner.add(ServerStatusEnum.OFFLINE.getValue());
            }else if(item.getState().equals(ServerStatusEnum.ONLINE.getCode())){
                stringJoiner.add(ServerStatusEnum.ONLINE.getValue());
            }else if(item.getState().equals(ServerStatusEnum.UNAUTH.getCode())){
                stringJoiner.add(ServerStatusEnum.UNAUTH.getValue());
            }

            if(item.getConnectType().equals(1)){
                stringJoiner.add("SSH");
            } else if(item.getConnectType().equals(2)){
                stringJoiner.add("PASSWORD");
            }

            if(null != item.getCreateUser() && null != item.getCreateUser().getNickName()){
                stringJoiner.add(item.getCreateUser().getNickName());
            }

            // 简单布尔表达式
            Boolean flag = false;
            if(key.contains("&")){
                for (String a : key.split("&")) {
                    flag = Boolean.logicalAnd(flag,stringJoiner.toString().contains(a));
                }
            }
            if(key.contains("|")){
                for (String a : key.split("|")) {
                    flag = Boolean.logicalOr(flag,stringJoiner.toString().contains(a));
                }
            }
            if(stringJoiner.toString().contains(key) || flag) needRetureServers.add(item);
        }



        int totalCount = needRetureServers.size();

        if(totalCount != 0) {
            // 处理排序
            if(searchDto.getSort().equals("state")){
                needRetureServers = needRetureServers.stream().sorted((e1, e2)->{
                    return (searchDto.getOrder().equals("asc")) ? e1.getState() - e2.getState() : e2.getState() - e1.getState();
                }).collect(Collectors.toList());
            }else if(searchDto.getSort().equals("create_user_id")){
                needRetureServers = needRetureServers.stream().sorted((e1, e2)->{
                    return (searchDto.getOrder().equals("asc")) ? e1.getCreateUserId().compareTo(e2.getCreateUserId()) : e2.getCreateUserId().compareTo(e1.getCreateUserId());
                }).collect(Collectors.toList());
            }
            // 处理分页
            if(searchDto.getMax() < totalCount){
                needRetureServers = needRetureServers.subList(searchDto.getOffset(),Integer.min(searchDto.getOffset() + searchDto.getMax(),totalCount));
            }
        }
        return new Pagination<>(searchDto.getMax(), searchDto.getPageNum(), totalCount, needRetureServers);
    }

    public void ifServeHasPublicKeySynUser(){

    }

}
